package com.zmn.mcc.dubbo.impl.staff;

import com.alibaba.fastjson.JSONObject;
import com.zmn.common.constant.GlobalConsts;
import com.zmn.common.dto.LoginStaff;
import com.zmn.common.dto.VtDTO;
import com.zmn.common.dto2.Option;
import com.zmn.common.dto2.OptionData;
import com.zmn.common.dto2.ResponseDTO;
import com.zmn.common.utils.collection.CollectionUtil;
import com.zmn.common.utils.date.DateUtil;
import com.zmn.common.utils.number.NumberUtil;
import com.zmn.common.utils.reflect.BeanMapper;
import com.zmn.common.utils.string.StringUtil;
import com.zmn.manager.common.database.annotation.ReadOnlyConnection;
import com.zmn.mcc.business.interfaces.dept.DeptBService;
import com.zmn.mcc.business.interfaces.staff.StaffBService;
import com.zmn.mcc.cache.DeptCache;
import com.zmn.mcc.cache.StaffCache;
import com.zmn.mcc.common.constant.StaffChangeLogConsts;
import com.zmn.mcc.common.constant.StaffConsts;
import com.zmn.mcc.common.constant.StaffOperateTypeConsts;
import com.zmn.mcc.common.dictionary.StaffDict;
import com.zmn.mcc.common.dto.base.PageDRO;
import com.zmn.mcc.common.dto.cc.CCStaffDRO;
import com.zmn.mcc.common.dto.cc.UpdateQuery;
import com.zmn.mcc.common.dto.staff.*;
import com.zmn.mcc.common.enums.MunicipalityEnum;
import com.zmn.mcc.dubbo.dto.DubboConsts;
import com.zmn.mcc.dubbo.interfaces.staff.StaffListRemoteService;
import com.zmn.mcc.manager.config.MccConfig;
import com.zmn.mcc.model.dto.OrgDeptDto;
import com.zmn.mcc.model.dto.staff.McStaffSimpleDTO;
import com.zmn.mcc.model.entity.dept.McDept;
import com.zmn.mcc.model.entity.organize.McOrganize;
import com.zmn.mcc.model.entity.role.McRole;
import com.zmn.mcc.model.entity.role.McRoleStaff;
import com.zmn.mcc.model.entity.staff.McStaff;
import com.zmn.mcc.model.entity.staff.McStaffQuery;
import com.zmn.mcc.model.entity.staff.StaffIdAndBsUserId;
import com.zmn.mcc.model.entity.staff.StaffIdAndDTalkId;
import com.zmn.mcc.model.entity.staff.staffchangelog.StaffChangeLog;
import com.zmn.mcc.model.entity.staff.staffleaveoffice.StaffLeaveOffice;
import com.zmn.mcc.model.entity.staff.staffleaveoffice.StaffLeaveOfficeQuery;
import com.zmn.mcc.services.interfaces.dept.DeptService;
import com.zmn.mcc.services.interfaces.organize.OrganizeService;
import com.zmn.mcc.services.interfaces.role.RoleService;
import com.zmn.mcc.services.interfaces.role.RoleStaffService;
import com.zmn.mcc.services.interfaces.staff.StaffService;
import com.zmn.mcc.services.interfaces.staff.staffchangelog.StaffChangeLogService;
import com.zmn.mcc.services.interfaces.staff.staffleaveoffice.StaffLeaveOfficeService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.dubbo.config.annotation.Service;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.BeansException;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cglib.beans.BeanCopier;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author heguanghua
 * @since 2020/06/04 17:00
 */
@Service(version = DubboConsts.INTERFACE_VERSION, validation = "true")
@Slf4j
public class StaffListRemoteServiceImpl implements StaffListRemoteService {
    private final Logger logger = LoggerFactory.getLogger(StaffListRemoteServiceImpl.class);

    private static final String TAG = "员工dubbo接口";

    private static LoginStaff loginStaff;

    @Resource
    private StaffService staffService;

    @Resource
    private StaffBService staffBService;

    @Resource
    private StaffCache staffCache;
    @Resource
    private DeptCache deptCache;
    @Resource
    private DeptBService deptBService;

    @Resource
    private OrganizeService organizeService;

    @Resource
    private StaffChangeLogService staffChangeLogService;

    @Resource
    private StaffLeaveOfficeService staffLeaveOfficeService;

    @Resource
    private RoleStaffService roleStaffService;
    @Resource
    private RoleService roleService;

    @Resource
    private DeptService deptService;

    @Resource
    private MccConfig config;

    BeanCopier staffDroCopier = BeanCopier.create(McStaff.class, StaffDRO.class, false);

    @Override
    @ReadOnlyConnection
    public ResponseDTO<StaffDRO> getStaff(Integer staffId) {

        if (NumberUtil.isNullOrZero(staffId)) {
            return ResponseDTO.fail("没有指定员工ID");
        }

        McStaff staff = staffCache.getStaff(staffId);

        if (staff == null) {
            return ResponseDTO.fail("用户不存在");
        }

        // 对象转换
        StaffDRO staffDRO = new StaffDRO();
        staffDroCopier.copy(staff, staffDRO, null);

        logger.info(String.format("[%s]取得员工对象,staff:[%s]", TAG, JSONObject.toJSONString(staff)));
        return ResponseDTO.success(staffDRO, "OK");
    }

    @Override
    public ResponseDTO<StaffDRO> getStaffById(Integer staffId) {
        if (NumberUtil.isNullOrZero(staffId)) {
            return ResponseDTO.fail("没有指定员工ID");
        }

        McStaff staff = staffCache.getStaff(staffId);

        if (staff == null) {
            return ResponseDTO.fail("用户不存在");
        }
        // 对象转换
        StaffDRO staffDRO = new StaffDRO();
        staffDroCopier.copy(staff, staffDRO, null);

        logger.info(String.format("[%s]取得员工对象,staff:[%s]", TAG, JSONObject.toJSONString(staff)));
        return ResponseDTO.success(staffDRO, "OK");
    }

    @Override
    public ResponseDTO<StaffDRO> getStaffLeaderById(Integer staffId) {
        if (NumberUtil.isNullOrZero(staffId)) {
            return ResponseDTO.fail("没有指定员工ID");
        }
        McStaff staff = staffCache.getStaff(staffId);
        if (staff == null) {
            return ResponseDTO.fail("员工不存在");
        }
        Integer leaderId = staff.getLeaderId();
        if (NumberUtil.isNullOrZero(leaderId)) {
            return ResponseDTO.fail("员工没有直属领导");
        }
        McStaff staffLeader = staffCache.getStaff(leaderId);
        if (staffLeader == null) {
            return ResponseDTO.fail("员工领导不存在");
        }
        // 对象转换
        StaffDRO staffDRO = new StaffDRO();
        staffDroCopier.copy(staffLeader, staffDRO, null);

        logger.info(String.format("[%s]取得员工对象,staff:[%s]", TAG, JSONObject.toJSONString(staffLeader)));
        return ResponseDTO.success(staffDRO, "OK");
    }

    @Override
    public ResponseDTO<List<StaffDRO>> getSubStaffByLeaderId(Integer staffId) {
        if (NumberUtil.isNullOrZero(staffId)) {
            return ResponseDTO.fail("没有指定员工ID");
        }
        McStaff staff = staffCache.getStaff(staffId);
        if (staff == null) {
            return ResponseDTO.fail("员工不存在");
        }
        McStaffQuery query = new McStaffQuery();
        query.setLeaderId(staffId);
        List<McStaff> mcStaffs = staffBService.listByQuery(query);
        List<StaffDRO> staffDROS = BeanMapper.mapList(mcStaffs, StaffDRO.class);

        return ResponseDTO.success(staffDROS);
    }

    @Override
    @ReadOnlyConnection
    public ResponseDTO<StaffDRO> getStaffByDingTalkId(String dingTalkId) {

        if (StringUtil.isBlank(dingTalkId)) {
            return ResponseDTO.fail("没有指定员工钉钉ID");
        }
        McStaffQuery query = new McStaffQuery();
        query.setDTalkId(dingTalkId);
        McStaff mcStaff = staffService.findStaffByDingTalkId(dingTalkId);
        if (Objects.isNull(mcStaff)) {
            return ResponseDTO.fail("未查询到员工信息");
        }

        // 只返回必要的信息
        StaffDRO staffDRO = new StaffDRO();
        BeanUtils.copyProperties(mcStaff, staffDRO);
        return ResponseDTO.success(staffDRO);
    }

    @Override
    @ReadOnlyConnection
    public ResponseDTO<Integer> getWorkPlaceCity(Integer staffId) {

        Integer workPlaceCity = staffCache.getWorkPlaceCity(staffId);
        return ResponseDTO.success(workPlaceCity, "查询成功");
    }

    @Override
    public ResponseDTO<List<CCStaffDRO>> listStaffByUpdateTime(UpdateQuery query) {

        if (Objects.isNull(query.getFrom()) || Objects.isNull(query.getTo())) {
            return ResponseDTO.fail("更新起止时间不能为空");
        }
        try {
            McStaffQuery query2 = new McStaffQuery();
            BeanUtils.copyProperties(query, query2);
            List<McStaff> result = Optional.ofNullable(staffService.listPageByQuery(query2)).orElse(Collections.emptyList());
            List<CCStaffDRO> result2 = BeanMapper.mapList(result, CCStaffDRO.class);
            return ResponseDTO.success(result2);
        } catch (BeansException e) {
            log.error("listStaffByUpdateTime查询失败,原因:{}", e.getMessage(), e);
            return ResponseDTO.fail("查询失败，程序异常");
        }
    }

    @Override
    @ReadOnlyConnection
    public ResponseDTO<List<VtDTO>> listStaffVtByQueryDIO(StaffQueryDIO query) {

        List<McStaff> staffs = this.listStaffByQueryBase(query);

        // 对象转换
        List<VtDTO> items = this.parseToVtDTO(staffs);

        logger.info(String.format("[%s]取得员工Vt对象列表,query:[%s]", TAG, JSONObject.toJSONString(query)));
        return ResponseDTO.success(items, "OK");
    }

    @Override
    @ReadOnlyConnection
    public ResponseDTO<List<StaffDRO>> listStaffByQueryDIO(StaffQueryDIO query) {

        List<McStaff> staffs = this.listStaffByQueryBase(query);

        // 对象转换
        List<StaffDRO> items = this.parseToStaffDRO(staffs);

        logger.info(String.format("[%s]取得员工对象列表,query:[%s]", TAG, JSONObject.toJSONString(query)));
        return ResponseDTO.success(items, "OK");
    }

    @Override
    @ReadOnlyConnection
    public ResponseDTO<List<VtDTO>> listStaffVtBySimpleQueryDIO(StaffSimpleQueryDIO query) {

        List<McStaff> staffs = this.listStaffBySimpleQueryBase(query);

        // 对象转换
        List<VtDTO> items = this.parseToVtDTO(staffs);

        logger.info(String.format("[%s]取得员工Vt对象列表,query:[%s]", TAG, JSONObject.toJSONString(query)));
        return ResponseDTO.success(items, "OK");
    }

    /**
     * 根据条件搜索查询部门下的所有员工(包含所有子部门，部门id列表必传)，返回员工vt对象列表
     *
     * @param query 简化的员工查询入参对象
     * @return ResponseDTO<List < VtDTO>>
     * @author xujie
     * @since 2021-05-17
     */
    @Override
    @ReadOnlyConnection
    public ResponseDTO<List<VtDTO>> listDeptAndSubDeptStaffVtBySimpleQueryDIO(StaffSimpleQueryDIO query) {

        if (query == null || query.getDeptIds() == null) {
            return ResponseDTO.fail("搜索查询部门下的所有子部门员工，部门id列表不能为null");
        }
        List<VtDTO> allSub = new ArrayList<>();
        List<Integer> deptIds = query.getDeptIds();
        for (; ; ) {
            List<VtDTO> subList = deptService.listSubDeptVtByOrgIdsAndDeptIds(query.getOrgIds(), deptIds);
            if (subList == null || subList.size() == 0) {
                break;
            }
            allSub.addAll(subList);
            deptIds = subList.stream().map(VtDTO::getValue).collect(Collectors.toList());
        }
        query.getDeptIds().addAll(allSub.stream().map(VtDTO::getValue).collect(Collectors.toList()));
        return listStaffVtBySimpleQueryDIO(query);
    }

    @Override
    @ReadOnlyConnection
    public ResponseDTO<List<StaffDRO>> listStaffBySimpleQueryDIO(StaffSimpleQueryDIO query) {

        List<McStaff> staffs = this.listStaffBySimpleQueryBase(query);

        // 对象转换
        List<StaffDRO> items = this.parseToStaffDRO(staffs);

        logger.info(String.format("[%s]取得员工对象列表,query:[%s]", TAG, JSONObject.toJSONString(query)));
        return ResponseDTO.success(items, "OK");
    }

    @Override
    public ResponseDTO<PageDRO<StaffLittleDRO>> listPageStaffByDIO(StaffQueryDIO query) {

        if (NumberUtil.isNullOrZero(query.getPageSize()) || query.getPageSize() > 100) {
            query.setPageSize(100);
        }
        if (NumberUtil.isNullOrZero(query.getPageIndex())) {
            query.setPageIndex(1);
        }
        try {
            McStaffQuery staffQuery = new McStaffQuery();
            BeanUtils.copyProperties(query, staffQuery);

            staffQuery.setStatus(GlobalConsts.YES);
            staffQuery.setStaffStatusList(Arrays.asList(StaffConsts.STAFF_STATUS_PROBATION, StaffConsts.STAFF_STATUS_NORMAL, StaffConsts.STAFF_STATUS_TO_HIRED,
                    StaffConsts.STAFF_STATUS_CALL_OUT, StaffConsts.STAFF_STATUS_IN, StaffConsts.STAFF_STATUS_RETIRE, StaffConsts.STAFF_STATUS_NO_NORMAL));

            List<StaffLittleDRO> staffLittleDROS = Optional.ofNullable(staffService.listPageInfoByQuery(staffQuery))
                    .orElse(Collections.emptyList())
                    .stream()
                    .map(mm -> {
                        StaffLittleDRO staffLittleDRO = new StaffLittleDRO();
                        BeanUtils.copyProperties(mm, staffLittleDRO);
                        staffLittleDRO.setTypeName(StaffDict.getRoleTypeName(mm.getType()));
                        McDept mcDept = Optional.ofNullable(deptCache.getDept(mm.getDeptId())).orElseGet(McDept::new);
                        staffLittleDRO.setDeptName(mcDept.getDeptName());
                        return staffLittleDRO;
                    }).collect(Collectors.toList());
            PageDRO<StaffLittleDRO> result = PageDRO.init(staffLittleDROS, staffQuery.getTotalCount());
            return ResponseDTO.success(result);
        } catch (BeansException e) {
            logger.error("StaffListRemoteServiceImpl.listPageStaffByDIO查询失败,原因:{}", e.getMessage(), e);
            return ResponseDTO.fail("查询失败，程序异常");
        }
    }

    @Override
    @ReadOnlyConnection
    public ResponseDTO<List<StaffDRO>> listStaffByKeyword(String keyword, Integer status) {

        if (StringUtil.isBlank(keyword)) {
            return ResponseDTO.fail("关键词不能为空");
        }

        List<McStaff> staffs = staffService.listSimpleByKeyword(keyword, status);

        // 对象转换
        List<StaffDRO> items = parseToStaffDRO(staffs);

        logger.info(String.format("[%s]取得员工对象列表,keyword:[%s],status:[%s]", TAG, keyword, status));
        return ResponseDTO.success(items, "OK");
    }

    @Override
    @ReadOnlyConnection
    public ResponseDTO<List<StaffDRO>> listStaffByRoleId(Integer roleId, Integer status) {

        if (NumberUtil.isNullOrZero(roleId)) {
            return ResponseDTO.fail("没有指定角色ID");
        }

        List<McStaff> staffs = staffService.listSimpleByRoleId(roleId, status);

        // 对象转换
        List<StaffDRO> items = parseToStaffDRO(staffs);

        logger.info(String.format("[%s]取得员工对象列表,roleId:[%s],status:[%s]", TAG, roleId, status));
        return ResponseDTO.success(items, "OK");
    }

    @Override
    @ReadOnlyConnection
    public ResponseDTO<List<StaffDRO>> listStaffByRoleIds(List<Integer> roleIds, Integer status) {
        if (CollectionUtil.isNullOrEmpty(roleIds)) {
            return ResponseDTO.fail("没有指定角色IDS");
        }

        List<McStaff> staffs = staffService.listSimpleByRoleIds(roleIds, status);

        // 对象转换
        List<StaffDRO> items = parseToStaffDRO(staffs);

        logger.info(String.format("[%s]取得员工对象列表,roleIds:[%s],status:[%s]", TAG, roleIds, status));
        return ResponseDTO.success(items, "OK");
    }

    @Override
    @ReadOnlyConnection
    public ResponseDTO<List<StaffSimpleDRO>> listStaffByRoleIdsIncludeRoleId(List<Integer> roleIds, Integer status) {
        if (CollectionUtil.isNullOrEmpty(roleIds)) {
            return ResponseDTO.fail("没有指定角色IDS");
        }

        List<McStaffSimpleDTO> staffs = staffService.listStaffByRoleIdsIncludeRoleId(roleIds, status);

        // 对象转换
        List<StaffSimpleDRO> items = parseToStaffSimpleDRO(staffs);

        logger.info(String.format("[%s]取得员工对象列表,roleIds:[%s],status:[%s]", TAG, roleIds, status));
        return ResponseDTO.success(items, "OK");
    }


    @Override
    @ReadOnlyConnection
    public ResponseDTO<List<StaffDRO>> listStaffByDeptIds(List<Integer> deptIds, Integer status) {

        if (CollectionUtil.isNullOrEmpty(deptIds)) {
            return ResponseDTO.fail("没有指定部门ID");
        }

        List<McStaff> staffs = staffService.listSimpleByDeptIds(deptIds, status);

        // 对象转换
        List<StaffDRO> items = parseToStaffDRO(staffs);

        logger.info(String.format("[%s]取得员工对象列表,deptIds:[%s],status:[%s]", TAG, deptIds, status));
        return ResponseDTO.success(items, "OK");
    }

    @Override
    @ReadOnlyConnection
    public ResponseDTO<List<VtDTO>> listStaffVtByDeptIdsAndNumber(List<Integer> deptIds, Integer status, Integer number) {
        if (CollectionUtil.isNullOrEmpty(deptIds)) {
            return ResponseDTO.fail("没有指定部门ID");
        }

        McStaffQuery query = new McStaffQuery();
        query.setDeptIds(deptIds);
        query.setStatus(status);
        if (NumberUtil.isPositiveInteger(number)) {
            query.setNumber(number > DubboConsts.DUBBO_RESULT_MAX_NUMBER ? DubboConsts.DUBBO_RESULT_MAX_NUMBER : number);
        }

        List<McStaff> staffs = staffService.listSimpleByQuery(query);

        // 对象转换
        List<VtDTO> items = staffs.stream().map(mcStaff -> new VtDTO(mcStaff.getStaffId(), mcStaff.getRealName())).distinct().collect(Collectors.toList());

        logger.info(String.format("[%s]取得员工对象列表,deptIds:[%s],status:[%s]", TAG, deptIds, status));
        return ResponseDTO.success(items, "OK");
    }

    @Override
    public ResponseDTO<List<Integer>> listStaffIdByDeptIds(List<Integer> deptIds) {

        if (CollectionUtil.isNullOrEmpty(deptIds)) {
            return ResponseDTO.fail("没有指定部门ID集合");
        }
        try {
            List<Integer> staffIds = Optional.ofNullable(staffService.listStaffIdByDeptIds(deptIds)).orElse(Collections.emptyList());
            return ResponseDTO.success(staffIds, "OK");
        } catch (Exception e) {
            logger.error("StaffListRemoteServiceImpl.listStaffIdByDeptIds查询失败,原因:{}", e.getMessage(), e);
            return ResponseDTO.fail("查询失败，程序异常");
        }
    }

    @Override
    @ReadOnlyConnection
    public ResponseDTO<List<StaffDRO>> listStaffByStaffIds(List<Integer> staffIds, Integer status) {

        if (CollectionUtil.isNullOrEmpty(staffIds)) {
            return ResponseDTO.fail("没有指定员工ID");
        }

        List<McStaff> staffs = staffService.listSimpleByStaffIds(staffIds, status);

        // 对象转换
        List<StaffDRO> items = parseToStaffDRO(staffs);

        logger.info(String.format("[%s]取得员工对象列表,staffIds:[%s],status:[%s]", TAG, staffIds, status));
        return ResponseDTO.success(items, "OK");
    }

    @Override
    @ReadOnlyConnection
    public ResponseDTO<List<StaffDRO>> listSubAllDeptStaffBySimpleQueryDIO(StaffSimpleQueryDIO query) {
        List<VtDTO> subAllDeptVtList = deptBService.listSubAllDeptIncludeSelf(query.getDeptIds(), GlobalConsts.YES);
        if (CollectionUtils.isNotEmpty(subAllDeptVtList)) {
            query.setDeptIds(subAllDeptVtList.stream().map(e -> e.getValue()).collect(Collectors.toList()));
        }

        return listStaffBySimpleQueryDIO(query);
    }

    @Override
    public ResponseDTO<List<StaffDRO>> listSubAllDeptStaffByDeptId(StaffSimpleQueryDIO query) {
        List<VtDTO> subAllDeptVtList = deptBService.listSubAllDeptIncludeSelf(query.getDeptIds(), GlobalConsts.YES);
        if (CollectionUtils.isNotEmpty(subAllDeptVtList)) {
            query.setDeptIds(subAllDeptVtList.stream().map(e -> e.getValue()).collect(Collectors.toList()));
        }

        McStaffQuery staffQuery = new McStaffQuery();
        staffQuery.setKeyword(query.getKeyword());
        staffQuery.setDeptIds(query.getDeptIds());
        staffQuery.setOrgIds(query.getOrgIds());
        List<McStaff> staffs = staffService.listSubStaffByQuery(staffQuery);

        // 对象转换
        List<StaffDRO> items = this.parseToStaffDRO(staffs);

        logger.info(String.format("[%s]取得员工对象列表,query:[%s]", TAG, JSONObject.toJSONString(query)));
        return ResponseDTO.success(items, "OK");
    }

    @Override
    public ResponseDTO<List<VtDTO>> listSubAllDeptStaffVtByDeptId(StaffSimpleQueryDIO query) {
        List<VtDTO> subAllDeptVtList = deptBService.listSubAllDeptIncludeSelf(query.getDeptIds(), GlobalConsts.YES);
        if (CollectionUtils.isNotEmpty(subAllDeptVtList)) {
            query.setDeptIds(subAllDeptVtList.stream().map(e -> e.getValue()).collect(Collectors.toList()));
        }
        McStaffQuery staffQuery = new McStaffQuery();
        staffQuery.setKeyword(query.getKeyword());
        staffQuery.setDeptIds(query.getDeptIds());
        staffQuery.setOrgIds(query.getOrgIds());

        List<VtDTO> staffs = Optional.ofNullable(staffService.listSubStaffByQuery(staffQuery))
                .orElse(Collections.emptyList())
                .stream()
                .map(e -> new VtDTO(e.getStaffId(), e.getRealName()))
                .collect(Collectors.toList());
        return ResponseDTO.success(staffs, "OK");
    }

    @Override
    public ResponseDTO<OptionData<Integer>> listSubAllDeptStaffOptionsByDeptId(StaffSimpleQueryDIO query) {

        List<VtDTO> subAllDeptVtList = deptBService.listSubAllDeptIncludeSelf(query.getDeptIds(), GlobalConsts.YES);
        if (CollectionUtils.isNotEmpty(subAllDeptVtList)) {
            query.setDeptIds(subAllDeptVtList.stream().map(VtDTO::getValue).collect(Collectors.toList()));
        }
        McStaffQuery staffQuery = new McStaffQuery();
        staffQuery.setKeyword(query.getKeyword());
        staffQuery.setDeptIds(query.getDeptIds());
        staffQuery.setOrgIds(query.getOrgIds());

        List<Option<Integer>> staffs = Optional.ofNullable(staffService.listSubStaffByQuery(staffQuery))
                .orElse(Collections.emptyList())
                .stream()
                .map(e -> new Option<>(e.getStaffId(), e.getRealName() + "-" + StringUtil.formatHideMobile(e.getMobile()))
                )
                .collect(Collectors.toList());

        return ResponseDTO.success(new OptionData<>(staffs, staffs.size()), "OK");

    }

    @Override
    public ResponseDTO<List<BsStaffDro>> listBsStaffByBsUserIds(List<Integer> baUserIds) {
        log.info("根据北森员工ID查询员工信息开始：{}", baUserIds);

        if (CollectionUtil.isNullOrEmpty(baUserIds)) {
            return ResponseDTO.fail("没有指定北森员工ID");
        }

        List<McStaff> staffList = staffService.listBsStaffInfo(baUserIds);
        if (CollectionUtil.isNullOrEmpty(staffList)) {
            return ResponseDTO.success(new ArrayList<>(), "OK");
        }

        List<BsStaffDro> bsStaffDroList = staffList.stream().map(e -> {
            BsStaffDro dro = new BsStaffDro();
            BeanUtils.copyProperties(e, dro);
            // 转换职务
            List<Integer> roleIds = roleStaffService.listRoleIdByStaffId(e.getStaffId());
            if (CollectionUtil.isNotNullOrEmpty(roleIds)) {
                List<Integer> secondPostIds = roleIds.stream().filter(roleId -> Objects.isNull(e.getPostId()) || Objects.equals(e.getPostId(), roleId)).collect(Collectors.toList());
                dro.setSecondPostIds(secondPostIds);
            }
            // 转换直线经理
            if (Objects.nonNull(e.getLeaderId())) {
                McStaff leader = staffService.findByKey(e.getLeaderId());
                dro.setBsLeaderId(Objects.nonNull(leader) ? leader.getBsUserId() : null);
            }
            dro.setOperateType(StaffOperateTypeConsts.OPERATE_TYPE_SELECT);
            return dro;
        }).collect(Collectors.toList());

        List<Integer> staffIds = staffList.stream().map(McStaff::getStaffId).collect(Collectors.toList());
        StaffLeaveOfficeQuery leaveOfficeQuery = new StaffLeaveOfficeQuery();
        leaveOfficeQuery.setStaffIdList(staffIds);
        List<StaffLeaveOffice> leaveOfficeList = staffLeaveOfficeService.listByQuery(leaveOfficeQuery);
        if (CollectionUtil.isNotNullOrEmpty(leaveOfficeList)) {
            Map<Integer, Date> leaveOfficeTimeMap = leaveOfficeList.stream()
                    .collect(Collectors.toMap(StaffLeaveOffice::getStaffId, StaffLeaveOffice::getCreateTime, (e1, e2) -> e2));
            bsStaffDroList.stream().forEach(e -> e.setLeaveTime(leaveOfficeTimeMap.get(e.getStaffId())));
        }

        logger.info("[{}]取得员工对象列表,query:[{}]", TAG, JSONObject.toJSONString(staffIds));

        return ResponseDTO.success(bsStaffDroList, "OK");
    }

    @Override
    public ResponseDTO<String> saveBsStaffInfo(List<BsStaffDio> staffInfoList) {
        logger.info("[{}]同步更新北森员工数据开始，数据list集合：{}", TAG, staffInfoList);

        List<Integer> bsUserIds = staffInfoList.stream().map(BsStaffDio::getBsUserId).collect(Collectors.toList());
        //增加员工异动日志
        List<McStaff> oldStaffList = staffService.listBsStaffInfo(bsUserIds);
        addStaffChangeLog(staffInfoList, oldStaffList);

        List<BsStaffDio> insertList = staffInfoList.stream()
                .filter(e -> StaffOperateTypeConsts.OPERATE_TYPE_INSERT.equals(e.getOperateType())).collect(Collectors.toList());
        List<BsStaffDio> updateList = staffInfoList.stream()
                .filter(e -> StaffOperateTypeConsts.OPERATE_TYPE_UPDATE.equals(e.getOperateType())).collect(Collectors.toList());

        // 新增员工
        if (CollectionUtil.isNotNullOrEmpty(insertList)) {
            // 为了保证新增的一批员工，如果有上下级关系，下级能找到上级
            List<BsStaff> bsStaffList = buildBsStaffRelationship(insertList);
            recursionAdd(bsStaffList);
        }

        if (CollectionUtil.isNotNullOrEmpty(updateList)) {
            List<BsStaff> bsStaffList = buildBsStaffRelationship(updateList);
            recursionUpdate(bsStaffList);
        }

        //离职员工处理
        List<BsStaffDio> leaveStaff = staffInfoList.stream().filter(e -> null != e.getLeaveTime()).collect(Collectors.toList());
        if (CollectionUtil.isNotNullOrEmpty(leaveStaff)) {
            updateLeaveStaffInfo(leaveStaff);
        }

        logger.info("[{}]同步更新北森员工数据结束", TAG);

        return ResponseDTO.success("OK");
    }

    private void recursionUpdate(List<BsStaff> bsStaffList) {
        if (CollectionUtil.isNullOrEmpty(bsStaffList)) {
            return;
        }
        for (BsStaff bsStaff : bsStaffList) {
            if (!Objects.isNull(bsStaff.getStaffId())) {
                // 被修改的员工不存在时就不修改
                McStaff oldStaff = staffService.findByKey(bsStaff.getStaffId());
                if (Objects.isNull(oldStaff)) {
                    return;
                }

                McStaff mcStaff = new McStaff();
                BeanUtils.copyProperties(bsStaff, mcStaff);
                Date now = new Date();
                mcStaff.setUpdateTime(now);
                dealMunicipalityCityCode(mcStaff);
                OrgDeptDto orgDeptDto = deptBService.findSuborOrgDeptByBsDeptId(mcStaff.getDeptId());
                if (null != orgDeptDto) {
                    BeanUtils.copyProperties(orgDeptDto, mcStaff);
                }
                // 设置机构orgId
                McDept dept = Optional.ofNullable(deptCache.getDept(mcStaff.getDeptId())).orElse(new McDept());
                mcStaff.setOrgId(dept.getOrgId());
                mcStaff.setDeptName(dept.getDeptName());
                // 设置plat
                McOrganize mcOrganize = Optional.ofNullable(organizeService.findByKey(dept.getOrgId())).orElse(
                        new McOrganize());
                mcStaff.setPlat(mcOrganize.getPlat());
                mcStaff.setCompanyId(mcOrganize.getCompanyId());
                mcStaff.setStatus(Objects.equals(StaffConsts.STAFF_STATUS_LEAVE, mcStaff.getStaffStatus()) ? 1 : 2);
                // 转换直线经理
                if (Objects.nonNull(bsStaff.getBsLeaderId())) {
                    McStaff leader = staffService.findByBsUserId(bsStaff.getBsLeaderId());
                    mcStaff.setLeaderId(Objects.nonNull(leader) ? leader.getStaffId() : null);
                    mcStaff.setLeaderName(Objects.nonNull(leader) ? leader.getRealName() : null);
                } else {
                    mcStaff.setLeaderId(null);
                    mcStaff.setLeaderName(null);
                }
                // 还原主职
                McRole role = null;
                if (Objects.isNull(bsStaff.getPostId())) {
                    mcStaff.setPostId(oldStaff.getPostId());
                } else {
                    role = roleService.findByKey(bsStaff.getPostId());
                    mcStaff.setPostId(Objects.nonNull(role) ? role.getRoleId() : oldStaff.getPostId());
                }
                // 修改员工，如果修改失败，所有下级和职务都不处理
                try {
                    setOrgAndDept(mcStaff);
                    log.info("更新北森员工:{}",mcStaff);
                    mcStaff.setDTalkId(null);
                    staffService.updateBsStaff(mcStaff);
                } catch (Exception e) {
                    logger.error("更新北森员工:{}数据失败,原因:{}", mcStaff.getStaffId(), e.getMessage(), e);
                    continue;
                }
                // 处理角色，只有主职（即主角色）变更后才处理角色
                if (Objects.nonNull(bsStaff.getPostId()) && Objects.nonNull(role) && !Objects.equals(oldStaff.getPostId(), bsStaff.getPostId())) {
                    handleRole(mcStaff.getStaffId(), bsStaff.getPostId(), bsStaff.getSecondPostIds());
                }
            }
            // 递归的修改下级
            recursionUpdate(bsStaff.getSubordinates());
        }
    }

    /**
     * 描述: 设置将部门或者组织的null转为0
     *
     * @param mcStaff
     * @author jiafei
     * @since 2021/10/15 10:48
     */
    private void setOrgAndDept(McStaff mcStaff) {
        mcStaff.setOrgOneId(Objects.isNull(mcStaff.getOrgOneId()) ? 0 : mcStaff.getOrgOneId());
        mcStaff.setOrgTwoId(Objects.isNull(mcStaff.getOrgTwoId()) ? 0 : mcStaff.getOrgTwoId());
        mcStaff.setOrgThrId(Objects.isNull(mcStaff.getOrgThrId()) ? 0 : mcStaff.getOrgThrId());
        mcStaff.setDeptOneId(Objects.isNull(mcStaff.getDeptOneId()) ? 0 : mcStaff.getDeptOneId());
        mcStaff.setDeptTwoId(Objects.isNull(mcStaff.getDeptTwoId()) ? 0 : mcStaff.getDeptTwoId());
        mcStaff.setDeptThrId(Objects.isNull(mcStaff.getDeptThrId()) ? 0 : mcStaff.getDeptThrId());
        mcStaff.setDeptFourId(Objects.isNull(mcStaff.getDeptFourId()) ? 0 : mcStaff.getDeptFourId());
        mcStaff.setDeptFiveId(Objects.isNull(mcStaff.getDeptFiveId()) ? 0 : mcStaff.getDeptFiveId());
        mcStaff.setDeptId(Objects.isNull(mcStaff.getDeptId()) ? 0 : mcStaff.getDeptId());
    }

    private void recursionAdd(List<BsStaff> bsStaffList) {
        if (CollectionUtil.isNullOrEmpty(bsStaffList)) {
            return;
        }
        for (BsStaff bsStaff : bsStaffList) {
            if (!Objects.isNull(bsStaff.getStaffName())) {
                McStaff mcStaff = new McStaff();
                BeanUtils.copyProperties(bsStaff, mcStaff);
                Date now = new Date();
                dealMunicipalityCityCode(mcStaff);
                mcStaff.setCreateTime(now);
                mcStaff.setUpdateTime(now);
                mcStaff.setPlat(GlobalConsts.PLAT_MARK_ZMN);
                mcStaff.setStatus(Objects.equals(StaffConsts.STAFF_STATUS_LEAVE, mcStaff.getStaffStatus()) ? 1 : 2);

                // 通过北森部门Id 查询mcc 部门Id
                OrgDeptDto orgDeptDto = deptBService.findSuborOrgDeptByBsDeptId(mcStaff.getDeptId());
                if (null != orgDeptDto) {
                    BeanUtils.copyProperties(orgDeptDto, mcStaff);
                }
                // 设置机构orgId
                McDept dept = Optional.ofNullable(deptCache.getDept(mcStaff.getDeptId())).orElse(new McDept());
                mcStaff.setOrgId(dept.getOrgId());
                mcStaff.setDeptName(dept.getDeptName());
                mcStaff.setStatus(Objects.equals(StaffConsts.STAFF_STATUS_LEAVE, mcStaff.getStaffStatus()) ? 1 : 2);
                // 转换直线经理
                if (Objects.nonNull(bsStaff.getBsLeaderId())) {
                    McStaff leader = staffService.findByBsUserId(bsStaff.getBsLeaderId());
                    mcStaff.setLeaderId(Objects.nonNull(leader) ? leader.getStaffId() : null);
                    mcStaff.setLeaderName(Objects.nonNull(leader) ? leader.getRealName() : null);
                }
                // 保存员工
                ResponseDTO resp = staffBService.addStaff(mcStaff, getBsLoginStaff(), "");
                // 员工新增失败，下级全部不添加
                if (!resp.isSuccess()) {
                    logger.error("未能新增员工{},错误信息={}", mcStaff.getRealName(), resp.getMessage());
                    continue;
                }
                // 处理角色
                Integer staffId = (Integer) resp.getData();
                handleRole(staffId, bsStaff.getPostId(), bsStaff.getSecondPostIds());
            }
            // 递归的新增下级
            recursionAdd(bsStaff.getSubordinates());
        }
    }

    private void handleRole(Integer staffId, Integer postId, List<Integer> secondPostIds) {
        // 构建所有职务的集合
        List<Integer> postIds = new ArrayList<>();
        if (Objects.nonNull(postId)) {
            postIds.add(postId);
        }
        if (CollectionUtil.isNotNullOrEmpty(secondPostIds)) {
            postIds.addAll(secondPostIds);
        }

        // 排除不存在的职务和特殊职务
        List<Integer> validPostIds = postIds.stream().filter(e -> {
            McRole role = roleService.findByKey(e);
            return Objects.nonNull(role) && !config.getIgnoredRoleIds().contains(e);
        }).collect(Collectors.toList());

        // 加载员工的所有角色
        List<Integer> roleIds = roleStaffService.listRoleIdByStaffId(staffId);
        List<Integer> validRoleIds = roleIds.stream().filter(e -> !config.getIgnoredRoleIds().contains(e)).collect(Collectors.toList());

        // 数据分类
        List<Integer> removes = validRoleIds.stream().filter(item -> !validPostIds.contains(item)).collect(Collectors.toList());
        List<Integer> inserts = validPostIds.stream().filter(item -> !validRoleIds.contains(item)).collect(Collectors.toList());

        // 删除该删除的
        if (CollectionUtil.isNotNullOrEmpty(removes)) {
            removes.forEach(e -> roleStaffService.deleteByKey(e, staffId));
        }

        // 新增该新增的
        if (CollectionUtil.isNotNullOrEmpty(inserts)) {
            List<McRoleStaff> list = new ArrayList<>(inserts.size());
            inserts.forEach(e -> list.add(new McRoleStaff(e, staffId)));
            roleStaffService.insertByBatch(list);
        }

        //角色变动日志

        if (CollectionUtil.isNotNullOrEmpty(removes) || CollectionUtil.isNotNullOrEmpty(inserts)) {
            List<Integer> beforeRoleIds = validRoleIds;
            String roleHis = Optional.ofNullable(roleService.listByIds(beforeRoleIds)).orElse(Collections.emptyList())
                    .stream().map(McRole::getRoleName).collect(Collectors.joining(","));


            // 去掉删除的角色和添加新增的角色
            beforeRoleIds.removeAll(removes);
            beforeRoleIds.addAll(inserts);
            String roleNow = Optional.ofNullable(roleService.listByIds(beforeRoleIds)).orElse(Collections.emptyList())
                    .stream().map(McRole::getRoleName).collect(Collectors.joining(","));

            staffChangeLogService.insert(buildStaffChangeLog(staffId, StringUtil.isBlank(roleHis) ? "-" : roleHis,
                    StringUtil.isBlank(roleNow) ? "-" : roleNow, StaffChangeLogConsts.CHANGE_TYPE_EDIT_ROLE));
        }
    }

    /**
     * 构建北森员工的上下级关系
     *
     * @param staffList 北森员工列表
     * @return
     */
    private List<BsStaff> buildBsStaffRelationship(List<BsStaffDio> staffList) {
        // 检查列表为空
        if (CollectionUtil.isNullOrEmpty(staffList)) {
            return new ArrayList<>(0);
        }

        // 依次处理员工
        int size = staffList.size();
        List<BsStaff> rootList = new ArrayList<>(size);
        Map<Integer, BsStaff> bsStaffMap = new HashMap<>(size);
        for (BsStaffDio dio : staffList) {
            // 赋值员工对象
            Integer bsUserId = dio.getBsUserId();
            BsStaff bsStaff = bsStaffMap.get(bsUserId);
            if (Objects.isNull(bsStaff)) {
                bsStaff = new BsStaff();
                bsStaff.setSubordinates(new ArrayList<>());
                bsStaffMap.put(bsUserId, bsStaff);
            }
            BeanUtils.copyProperties(dio, bsStaff, "subordinates");
            // update:钉钉ID的数据，不需要通过北森系统同步。(2022-08-10)
            bsStaff.setDTalkId(null);

            // 根据上级标识处理
            Integer bsLeaderId = dio.getBsLeaderId();
            if (Objects.nonNull(bsLeaderId)) {
                // 构建上级对象
                BsStaff bsLeader = bsStaffMap.get(bsLeaderId);
                if (Objects.isNull(bsLeader)) {
                    bsLeader = new BsStaff();
                    bsLeader.setBsUserId(bsLeaderId);
                    bsLeader.setSubordinates(new ArrayList<>());
                    bsStaffMap.put(bsLeaderId, bsLeader);
                    // 添加上级对象，解决上级出现在下级后面的问题
                    BsStaff temp = bsLeader;
                    if (staffList.stream().noneMatch(item -> Objects.equals(item.getBsUserId(), temp.getBsUserId()))) {
                        rootList.add(bsLeader);
                    }
                }

                // 添加下级对象
                bsLeader.getSubordinates().add(bsStaff);
            } else {
                // 添加上级对象
                rootList.add(bsStaff);
            }
        }

        // 返回根员工对象
        return rootList;
    }

    @Override
    @Cacheable(cacheNames = "redis1h", key = "'staff:'+#p0+'permit:url:' + #p1")
    public ResponseDTO<Boolean> checkPermitBySatffIdAndUrl(Integer staffId, String url) {
        logger.info("checkPermitBySatffIdAndUrl params is {},{}", staffId, url);
        if (!NumberUtil.isPositiveInteger(staffId) || StringUtil.isBlank(url)) {
            return ResponseDTO.fail("员工id，权限url不能为空");
        }
        // 如果员工具有超级管理员角色，那么拥有所有权限
        boolean isSuperAdmin = staffBService.isSuperAdmin(staffId);
        if (isSuperAdmin) {
            return ResponseDTO.success(isSuperAdmin);
        }
        // 其他角色
        List<Integer> list = roleStaffService.listPermitBySatffIdAndUrl(staffId, url);
        return ResponseDTO.success(CollectionUtils.isNotEmpty(list));
    }

    @Override
    public ResponseDTO<List<StaffIdAndRealNameDRO>> listByRoleIdsAndDeptId(List<Integer> roleIds, Integer deptId) {

        List<Integer> staffIdList = roleStaffService.listStaffIdByRoleIdList(roleIds);
        if (staffIdList == null || staffIdList.size() == 0) {
            return ResponseDTO.success(new ArrayList<>(), "查询成功");
        }
        List<StaffIdAndRealNameDRO> staffIdAndRealNameList = staffService.listStaffIdByStaffIdListAndDeptIdAndStatus(staffIdList, deptId, GlobalConsts.YES);
        return ResponseDTO.success(staffIdAndRealNameList, "查询成功");
    }

    @Override
    public ResponseDTO<List<StaffIdAndDTalkIdDRO>> listStaffIdAndDTalkIdByStaffIdList(List<Integer> staffIdList) {

        List<StaffIdAndDTalkId> staffIdAndTalkIdList = staffService.listStaffIdAndDTalkIdByStaffIdList(staffIdList);
        List<StaffIdAndDTalkIdDRO> staffIdAndDTalkIdDROList = new ArrayList<>(staffIdList.size());
        staffIdAndTalkIdList.forEach(s -> {
            StaffIdAndDTalkIdDRO d = StaffIdAndDTalkIdDRO.builder()
                    .dTalkId(s.getDTalkId())
                    .staffId(s.getStaffId())
                    .build();
            staffIdAndDTalkIdDROList.add(d);
        });
        return ResponseDTO.success(staffIdAndDTalkIdDROList, "查询成功");
    }

    @Override
    public ResponseDTO<String> getDTalkIdByMail(String mail) {
        String dTalkId = staffBService.getDTalkIdByMail(mail);
        return ResponseDTO.success(dTalkId);
    }

    @Override
    public ResponseDTO<List<StaffIdAndBsUserIdDRO>> listStaffIdAndBsUserId() {
        List<StaffIdAndBsUserId> list = staffService.listStaffIdAndBsUserId();
        List<StaffIdAndBsUserIdDRO> result = new ArrayList<>(list.size());
        for (StaffIdAndBsUserId item : list) {
            StaffIdAndBsUserIdDRO dro = StaffIdAndBsUserIdDRO.builder().staffId(item.getStaffId()).bsUserId(item.getBsUserId()).build();
            result.add(dro);
        }
        return ResponseDTO.success(result, "查询成功");
    }

    @Override
    public ResponseDTO<String> saveStaffWorkTime(List<StaffWorkTimeDIO> list) {
        logger.info("同步更新员工工作时间，请求数据：{}", list);

        // 参数校验
        if (CollectionUtil.isNullOrEmpty(list)) {
            return ResponseDTO.fail("请求数据为空");
        }

        // 查询员工数据
        List<Integer> staffIds = list.stream().map(StaffWorkTimeDIO::getStaffId).collect(Collectors.toList());
        McStaffQuery query = new McStaffQuery();
        query.setStaffIds(staffIds);
        List<McStaff> staffs = staffService.listByQuery(query);
        if (CollectionUtil.isNullOrEmpty(staffs)) {
            return ResponseDTO.success("同步成功");
        }

        // 记录异动日志
        List<StaffChangeLog> changeLogs = new ArrayList<>();
        for (McStaff staff : staffs) {
            Optional<StaffWorkTimeDIO> optional = list.stream().filter(e -> Objects.equals(e.getStaffId(), staff.getStaffId())).findFirst();
            if (!optional.isPresent()) {
                continue;
            }
            StaffWorkTimeDIO dio = optional.get();
            if (!Objects.equals(staff.getStartWorkTime(), dio.getStartWorkTime())
                    || !Objects.equals(staff.getStopWorkTime(), dio.getStopWorkTime())) {
                String before = String.format("%s - %s", Objects.isNull(staff.getStartWorkTime()) ? "-" : staff.getStartWorkTime(), Objects.isNull(staff.getStopWorkTime()) ? "-" : staff.getStopWorkTime());
                String after = String.format("%s - %s", Objects.isNull(dio.getStartWorkTime()) ? "-" : dio.getStartWorkTime(), Objects.isNull(dio.getStopWorkTime()) ? "-" : dio.getStopWorkTime());
                StaffChangeLog changeLog = buildStaffChangeLog(staff.getStaffId(), before, after, StaffChangeLogConsts.CHANGE_TYPE_WORK_TIME);
                changeLogs.add(changeLog);
            }
        }
        if (CollectionUtil.isNotNullOrEmpty(changeLogs)) {
            staffChangeLogService.batchInsert(changeLogs);
        }

        // 更新工作时间
        for (McStaff staff : staffs) {
            Optional<StaffWorkTimeDIO> optional = list.stream().filter(e -> Objects.equals(e.getStaffId(), staff.getStaffId())).findFirst();
            if (!optional.isPresent()) {
                continue;
            }
            StaffWorkTimeDIO dio = optional.get();
            staff.setStartWorkTime(dio.getStartWorkTime());
            staff.setStopWorkTime(dio.getStopWorkTime());
            staffService.updateWorkTime(staff);
        }

        return ResponseDTO.success("同步成功");
    }

    /**
     * 根据指定查询入参对象取得员工列表
     *
     * @param query 员工查询入参对象 {@link StaffQueryDIO}
     * @return
     */
    private List<McStaff> listStaffByQueryBase(StaffQueryDIO query) {
        McStaffQuery staffQuery = new McStaffQuery();
        staffQuery.setStaffName(query.getStaffName());
        staffQuery.setRealName(query.getRealName());
        staffQuery.setPlat(query.getPlat());
        staffQuery.setOrgTwoId(query.getOrgTwoId());
        staffQuery.setOrgThrId(query.getOrgThrId());
        staffQuery.setDeptId(query.getDeptId());
        staffQuery.setMobile(query.getMobile());
        staffQuery.setMail(query.getMail());
        staffQuery.setIdentityType(query.getIdentityType());
        staffQuery.setType(query.getType());
        staffQuery.setStatus(query.getStatus());
        staffQuery.setNumber(query.getPageSize());
        return staffService.listSimpleByQuery(staffQuery);
    }

    /**
     * 根据指定简化的查询入参对象取得员工列表
     *
     * @param query 简化的员工查询入参对象 {@link StaffSimpleQueryDIO}
     * @return
     */
    private List<McStaff> listStaffBySimpleQueryBase(StaffSimpleQueryDIO query) {
        McStaffQuery staffQuery = new McStaffQuery();
        staffQuery.setKeyword(query.getKeyword());
        staffQuery.setPlat(query.getPlat());
        staffQuery.setOrgTwoId(query.getOrgTwoId());
        staffQuery.setOrgThrId(query.getOrgThrId());
        staffQuery.setIdentityType(query.getIdentityType());
        staffQuery.setType(query.getType());
        staffQuery.setStatus(query.getStatus());
        staffQuery.setCompanyIds(query.getCompanyIds());
        staffQuery.setOrgIds(query.getOrgIds());
        staffQuery.setDeptIds(query.getDeptIds());
        staffQuery.setStaffStatusList(query.getStaffStatusList());
        return staffService.listSimpleByQuery(staffQuery);
    }

    /**
     * 把原始的员工对象McStaff转换为VtDTO对象
     *
     * @param staffs
     * @return List<StaffDRO>
     */
    private List<VtDTO> parseToVtDTO(List<McStaff> staffs) {

        List<VtDTO> items = new ArrayList<>();

        for (McStaff staff : staffs) {
            String text = String.format("%s<%s><%s>", staff.getRealName(), StringUtil.formatHideMobile(staff.getMobile()), StaffDict.getStatusName(staff.getStaffStatus()));
            items.add(new VtDTO(staff.getStaffId(), text));
        }
        return items;
    }

    /**
     * 把原始的员工对象McStaff转换为Dubbo出参对象
     *
     * @param staffs
     * @return List<StaffDRO>
     */
    private List<StaffDRO> parseToStaffDRO(List<McStaff> staffs) {

        List<StaffDRO> items = new ArrayList<>();

        // 对象转换
        BeanCopier copier = BeanCopier.create(McStaff.class, StaffDRO.class, false);
        for (McStaff staff : staffs) {
            StaffDRO staffDRO = new StaffDRO();
            copier.copy(staff, staffDRO, null);
            // 查询部门id
            McDept dept = Optional.ofNullable(deptCache.getDept(staff.getDeptId())).orElse(new McDept());
            staffDRO.setDeptName(dept.getDeptName());
            items.add(staffDRO);
        }
        return items;
    }


    /**
     * 把原始的员工对象MMcStaffSimpleDTO转换为Dubbo出参对象
     *
     * @param staffs
     * @return List<StaffSimpleDRO>
     */
    private List<StaffSimpleDRO> parseToStaffSimpleDRO(List<McStaffSimpleDTO> staffs) {

        List<StaffSimpleDRO> items = new ArrayList<>();

        // 对象转换
        BeanCopier copier = BeanCopier.create(McStaffSimpleDTO.class, StaffSimpleDRO.class, false);
        for (McStaffSimpleDTO staff : staffs) {
            StaffSimpleDRO staffDRO = new StaffSimpleDRO();
            copier.copy(staff, staffDRO, null);
            items.add(staffDRO);
        }
        return items;
    }

    /**
     * 北森离职信息批量更新
     */
    private void updateLeaveStaffInfo(List<BsStaffDio> leaveStaff) {
        logger.info("更新离职员工信息:{}", leaveStaff);
        List<Integer> bsUserId = leaveStaff.stream().map(BsStaffDio::getBsUserId).collect(Collectors.toList());
        List<McStaff> staffs = staffService.listBsStaffInfo(bsUserId);
        Map<Integer, Integer> staffIdMap = staffs.stream()
                .collect(Collectors.toMap(McStaff::getBsUserId, McStaff::getStaffId, (e1, e2) -> e2));
        leaveStaff.forEach(e -> {
            if (null == e.getStaffId()) {
                e.setStaffId(staffIdMap.get(e.getBsUserId()));
            }
        });
        List<Integer> staffIds = staffs.stream().map(McStaff::getStaffId).collect(Collectors.toList());
        StaffLeaveOfficeQuery query = new StaffLeaveOfficeQuery();
        query.setStaffIdList(staffIds);
        List<StaffLeaveOffice> leavedList = staffLeaveOfficeService.listByQuery(query);

        List<StaffLeaveOffice> staffLeaveOfficeList;
        //需要更新离职时间的员工
        if (CollectionUtil.isNotNullOrEmpty(leavedList)) {
            Map<Integer, Date> leaveTimeMap = leaveStaff.stream()
                    .collect(Collectors.toMap(BsStaffDio::getStaffId, BsStaffDio::getLeaveTime, (e1, e2) -> e2));
            staffLeaveOfficeList = leavedList.stream().map(e -> {
                StaffLeaveOffice staffLeaveOffice = new StaffLeaveOffice();
                staffLeaveOffice.setStaffId(e.getStaffId());
                staffLeaveOffice.setLastWorkTime(leaveTimeMap.get(e.getStaffId()));
                staffLeaveOffice.setCreateTime(leaveTimeMap.get(e.getStaffId()));
                return staffLeaveOffice;
            }).collect(Collectors.toList());
            staffLeaveOfficeList.forEach(e -> staffLeaveOfficeService.updateLeaveTime(e));

            List<Integer> leavedListStaffId = leavedList.stream()
                    .map(StaffLeaveOffice::getStaffId).collect(Collectors.toList());
            leaveStaff = leaveStaff.stream().filter(e -> !leavedListStaffId.contains(e.getStaffId()))
                    .collect(Collectors.toList());
        }
        //新增离职员工记录
        if (CollectionUtil.isNotNullOrEmpty(leaveStaff)) {
            staffLeaveOfficeList = leaveStaff.stream().map(e -> {
                StaffLeaveOffice staffLeaveOffice = new StaffLeaveOffice();
                staffLeaveOffice.setStaffId(e.getStaffId());
                staffLeaveOffice.setLastWorkTime(e.getLeaveTime());
                staffLeaveOffice.setCreateTime(e.getLeaveTime());
                return staffLeaveOffice;
            }).collect(Collectors.toList());
            staffLeaveOfficeService.batchInsertByBs(staffLeaveOfficeList);

            //新增离职记录
            List<StaffChangeLog> leaveLogList = leaveStaff.stream()
                    .map(e -> buildStaffChangeLog(e.getStaffId(), "-", "状态从正常修改为离职", StaffChangeLogConsts.CHANGE_TYPE_LEAVE))
                    .collect(Collectors.toList());
            staffChangeLogService.batchInsert(leaveLogList);
        }
    }

    /**
     * 比对员工信息
     *
     * @param bsStaffList
     * @param staffList
     */
    private void addStaffChangeLog(List<BsStaffDio> bsStaffList, List<McStaff> staffList) {
        List<StaffChangeLog> allChange = new ArrayList<>();
        for (BsStaffDio bsStaffDio : bsStaffList) {
            McStaff oldStaff = staffList.stream().filter(e -> e.getStaffId().equals(bsStaffDio.getStaffId()))
                    .findAny().orElse(null);
            try {
                List<StaffChangeLog> changeLogList = compareStaff(bsStaffDio, oldStaff);
                if (CollectionUtil.isNotNullOrEmpty(changeLogList)) {
                    allChange.addAll(changeLogList);
                }
            } catch (Exception e) {
                logger.error("员工异动信息出错入参 bsStaffDio={}, oldStaff={}", bsStaffDio, oldStaff);
                continue;
            }

        }
        if (CollectionUtil.isNotNullOrEmpty(allChange)) {
            staffChangeLogService.batchInsert(allChange);
        }
    }

    private List<StaffChangeLog> compareStaff(BsStaffDio bsStaff, McStaff oldStaff) {
        List<StaffChangeLog> changeLogList = new ArrayList<>();
        if (null == oldStaff) {
            return new ArrayList<>();
        }
        //员工类型
        if (!Objects.equals(bsStaff.getType(), oldStaff.getType())) {
            changeLogList.add(buildStaffChangeLog(bsStaff.getStaffId(), StaffDict.getRoleTypeName(oldStaff.getType()),
                    StaffDict.getRoleTypeName(bsStaff.getType()), StaffChangeLogConsts.CHANGE_TYPE_ROLE_TYPE));
        }
        //员工手机号
        if (!Objects.equals(bsStaff.getMobile(), oldStaff.getMobile())) {
            changeLogList.add(buildStaffChangeLog(bsStaff.getStaffId(), oldStaff.getMobile(),
                    bsStaff.getMobile(), StaffChangeLogConsts.CHANGE_TYPE_MOBILE));
        }

        McDept deptNow = Optional.ofNullable(deptService.findByBsDeptId(bsStaff.getDeptId())).orElse(new McDept());
        //所属组织
        Integer orgIdNow = Optional.ofNullable(deptCache.getDept(deptNow.getDeptId())).orElse(new McDept()).getOrgId();

        //所属部门
        if (!Objects.equals(orgIdNow, oldStaff.getOrgId())) {
            McOrganize companyHis = organizeService.findByKey(oldStaff.getOrgId());
            McOrganize companyNow = organizeService.findByKey(orgIdNow);
            changeLogList.add(buildStaffChangeLog(bsStaff.getStaffId(), Objects.isNull(companyHis) ? "-" : companyHis.getOrgName(),
                    Objects.isNull(companyNow) ? "-" : companyNow.getOrgName(), StaffChangeLogConsts.CHANGE_TYPE_EDIT_COMPANY));
        }

        if (!Objects.equals(deptNow.getDeptId(), oldStaff.getDeptId())) {
            McDept deptHis = deptBService.findByKey(oldStaff.getDeptId());

            changeLogList.add(buildStaffChangeLog(bsStaff.getStaffId(), Objects.isNull(deptHis) ? "-" : deptHis.getDeptName(),
                    Objects.isNull(deptNow.getDeptId()) ? "-" : deptNow.getDeptName(),
                    StaffChangeLogConsts.CHANGE_TYPE_EDIT_DEPT));
        }

        //职级 positionLevel
        if (!Objects.equals(bsStaff.getPositionLevel(), oldStaff.getPositionLevel())) {
            changeLogList.add(buildStaffChangeLog(bsStaff.getStaffId(), StaffDict.getLevelName(oldStaff.getPositionLevel()),
                    StaffDict.getLevelName(bsStaff.getPositionLevel()), StaffChangeLogConsts.CHANGE_TYPE_EDIT_POSITION));
        }

        //转正
        if (!Objects.equals(bsStaff.getBecomeFormalTime(), oldStaff.getBecomeFormalTime())) {
            changeLogList.add(buildStaffChangeLog(bsStaff.getStaffId(), null == oldStaff.getBecomeFormalTime() ? "" :
                            DateUtil.toString(oldStaff.getBecomeFormalTime(), DateUtil.FORMAT_DEFAULT),
                    null == bsStaff.getBecomeFormalTime() ? "" : DateUtil.toString(bsStaff.getBecomeFormalTime(), DateUtil.FORMAT_DEFAULT),
                    StaffChangeLogConsts.CHANGE_TYPE_EDIT_BECOME_FORMAL_TIME));
        }

        return changeLogList;
    }

    private StaffChangeLog buildStaffChangeLog(Integer staffId, String beforContent, String afterContent, Integer changeType) {
        StaffChangeLog staffChangeLog = new StaffChangeLog();
        staffChangeLog.setStaffId(staffId);
        staffChangeLog.setBeforContent(null == beforContent ? "-" : beforContent);
        staffChangeLog.setAfterContent(null == afterContent ? "-" : afterContent);
        staffChangeLog.setChangeType(changeType);
        staffChangeLog.setIp("-");
        staffChangeLog.setAbutmenterCity("-");
        staffChangeLog.setAbutmenterId(0);
        staffChangeLog.setAbutmenter("北森数据同步");
        staffChangeLog.setAbutmenterDeptId("");
        staffChangeLog.setAbutmenterDeptName("");
        staffChangeLog.setCreateTime(DateUtil.getNow());
        return staffChangeLog;
    }

    private LoginStaff getBsLoginStaff() {
        if (Objects.isNull(loginStaff)) {
            loginStaff = new LoginStaff();
            loginStaff.setStaffId(0);
            loginStaff.setRealName("北森数据同步");
            loginStaff.setDeptId(0);
            loginStaff.setDeptName("");
        }
        return loginStaff;
    }

    private void dealMunicipalityCityCode(McStaff staff) {
        if (MunicipalityEnum.BEIJING.getProvinceCode().equals(staff.getWorkPlaceProvince())) {
            staff.setWorkPlaceCity(MunicipalityEnum.BEIJING.getCityCode());
        }
        if (MunicipalityEnum.SHANGHAI.getProvinceCode().equals(staff.getWorkPlaceProvince())) {
            staff.setWorkPlaceCity(MunicipalityEnum.SHANGHAI.getCityCode());
        }
        if (MunicipalityEnum.TIANJIN.getProvinceCode().equals(staff.getWorkPlaceProvince())) {
            staff.setWorkPlaceCity(MunicipalityEnum.TIANJIN.getCityCode());
        }
        if (MunicipalityEnum.CHONGQING.getProvinceCode().equals(staff.getWorkPlaceProvince())) {
            staff.setWorkPlaceCity(MunicipalityEnum.CHONGQING.getCityCode());
        }
    }

    @Override
    public ResponseDTO<List<StaffBriefDRO>> listSimpleStaffByDeptIds(Integer deptOneId, List<Integer> deptTwoIds) {

        List<McStaff> mcStaffs = staffService.listSimpleStaffByDeptIds(deptOneId, deptTwoIds);
        // 对象转换
        List<StaffBriefDRO> items = BeanMapper.mapList(mcStaffs, StaffBriefDRO.class);
        return ResponseDTO.success(items, "OK");
    }

    @Override
    public ResponseDTO<EngineerBasicInfoDRO> getEngineerByStaffId(Integer staffId) {
        EngineerBasicInfoDRO basicInfoDRO = staffBService.getEngineerByStaffId(staffId);
        return ResponseDTO.success(basicInfoDRO);
    }
}
